/**
* @file app_upgrade.c
* @brief 应用升级文件
* @author liucx (liucx@fiberhome.com)
* @version 1.0
* @date 2020-12-01
* @copyright Copyright (c) 2020  烽火通信
***************************************************************
* @par 修改日志:
* <table>
* <tr><th>Date       <th>Version  <th>Author  <th>Description
* <tr><td>2020-12-01 <td>1.0      <td>liucx   <td>内容
* </table>
*/ 
#include "project_config.h"
#if BOARD_PCU_EN
#include "app_upgrade.h"
#include "project_board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"
#include "sha256.h"
#include "com_endian.h"
#include "app_control.h"
#include "common_interfaces.h"
#include <easyflash.h>
#include "msc.h"
#include "bsp_flash.h"
#include "bsp_log.h"
#include "iap.h"
#include "sha256.h"
#include "drvOsHal.h"
#include "msc.h"
TimerHandle_t  upgradeTimerId = NULL;
TimerHandle_t  upgrade_flag_cleanTimerId = NULL;
char temp[1024] ={0};
//sha256_context_t * upgrade_sha256_result;
/**
* @brief 升级重启
* @param bin            升级数据
* @param size           升级数据包大小
* @param offset         升级偏移量
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_flash_write(uint8_t *bin, uint16_t size, uint32_t offset)
{
    if(BSP_SUCCESS != iap_download(bin,size,&offset,APP_SIZE))
    {
        return ERROR_COM;
    }
    return OK;
}

/**
* @brief 升级清空块区
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_bank_erase(void)
{
    return iap_download_prepare();
}

/**
* @brief 升级重启定时器
* @param xTimer            定时器句柄
* @return uint8_t OK：成功  ERROR_COM：失败
*/
void upgrade_interface_reset(xTimerHandle xTimer )
{
    app_control_save();
    iap_upgrade_prepare();
}


/**
* @brief 升级标志清除定时器
* @param xTimer            定时器句柄
* @return uint8_t OK：成功  ERROR_COM：失败
*/
void upgrade_flag_clean(xTimerHandle xTimer )
{
	UPGRADE_VALUES_t upgrade_values;
	app_control_upgrade_values_get(&upgrade_values);
	upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
	app_control_upgrade_values_set(&upgrade_values);
}

/**
* @brief 升级标志清除定时器开启
*/
void upgrade_flag_clean_start( void )
{
	if(upgrade_flag_cleanTimerId != NULL)
	{
		if( xTimerIsTimerActive( upgrade_flag_cleanTimerId ) != pdFALSE ) 
		{
			xTimerStop(upgrade_flag_cleanTimerId,0);
		}
		xTimerDelete(upgrade_flag_cleanTimerId,0);
	}
	upgrade_flag_cleanTimerId = xTimerCreate("upgrade_flag_clean",pdMS_TO_TICKS(10*1000),pdFALSE,NULL,upgrade_flag_clean);
	xTimerStart(upgrade_flag_cleanTimerId,0);
}

				
				
				
/**
* @brief 升级控制命令回调
* @param src               数据包头
* @param indata            输入报文
* @param indata_len        输入报文长度
* @param outdata           输出报文
* @param outdata_len       输出报文长度
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_control(uint8_t *src, uint8_t * indata,uint16_t indata_len,uint8_t * outdata,uint16_t *outdata_len)
{

   uint8_t upgrade_source = 0;
   uint8_t upgrade_control_flag = 0;
   uint16_t offset = 0;
   uint32_t subfile_no = 0;
   uint32_t subfile_total_no = 0;
   UPGRADE_VALUES_t upgrade_values;
   char upgrade_version[UPGRADE_VERSION_LEN];
   char upgrade_sha256[UPGRADE_SHA256_LEN];
   if(src[1] == 0xE1)
   {
       upgrade_source = 1;
   }
   else if (src[1] == 0xE2)
   {
       upgrade_source = 2;
   }
   else if (src[1] == 0xE3)
   {
       upgrade_source = 3;
   }
   else
   {
       return ERROR_COM;
   }
   if(OK != app_control_upgrade_values_get(&upgrade_values))
   {
       return ERROR_COM;
   }
   POUT_STORE_CHAR(indata,upgrade_control_flag,offset);
   POUT_STORE_BUFF(indata,upgrade_version,offset,UPGRADE_VERSION_LEN);
   POUT_STORE_LONG(indata,subfile_total_no,offset);
   POUT_STORE_BUFF(indata,upgrade_sha256,offset,UPGRADE_SHA256_LEN);
   if(upgrade_values.upgrade_source == upgrade_source)
   {
       if( upgrade_control_flag ==  UPGRADE_START)
       {
//           if(strncmp(upgrade_version,upgrade_values.upgrade_version,UPGRADE_VERSION_LEN) == 0 && upgrade_values.upgrade_status != UPGRADE_STATUS_SUCCESS && upgrade_values.upgrade_status != UPGRADE_STATUS_FAIL )
//           {
//               /* 续传 */
//               if(0 != upgrade_values.wait_subfile_no)
//               {
//                   subfile_no = upgrade_values.wait_subfile_no;
//               }
//               else
//               {
//                   subfile_no = 1;
//               }
//           }
//           else
//           {
				if(OK != app_upgrade_bank_erase())
				{
				   return ERROR_COM;
				}
				upgrade_values.file_total_num = 0;
				upgrade_values.subfile_num = subfile_total_no;
				memcpy(upgrade_values.sha256,upgrade_sha256,UPGRADE_SHA256_LEN);
				memcpy(upgrade_values.upgrade_version,upgrade_version,UPGRADE_VERSION_LEN);
				upgrade_values.wait_subfile_no = 1;
				subfile_no = 1 ;
				upgrade_flag_clean_start();

//           }
       }
       else if (upgrade_control_flag ==  UPGRADE_STOP)
       {
           upgrade_values.upgrade_status = UPGRADE_STATUS_NO;
           subfile_no = 0;
       }
       else
       {
           /* 命令码错误 */
           return ERROR_COM;
       }
   }
   else if(upgrade_values.upgrade_source != 0)
   {
//       if(upgrade_values.upgrade_status == UPGRADE_STATUS_NO || upgrade_values.upgrade_status == UPGRADE_STATUS_SUCCESS ||upgrade_values.upgrade_status == UPGRADE_STATUS_FAIL || upgrade_values.upgrade_status == UPGRADE_STATUS_REBOOT)
//       {
           /* 重新执行命令 */
           if( upgrade_control_flag ==  UPGRADE_START)
           {
               if(OK != app_upgrade_bank_erase())
               {
                   return ERROR_COM;
               }
               upgrade_values.file_total_num = 0;
               upgrade_values.upgrade_source = upgrade_source;
               upgrade_values.subfile_num = subfile_total_no;
               memcpy(upgrade_values.sha256,upgrade_sha256,UPGRADE_SHA256_LEN);
               memcpy(upgrade_values.upgrade_version,upgrade_version,UPGRADE_VERSION_LEN);
               upgrade_values.wait_subfile_no = 1;
               subfile_no = 1;
			   upgrade_flag_clean_start();
           }
           else if (upgrade_control_flag ==  UPGRADE_STOP)
           {
               upgrade_values.upgrade_status = UPGRADE_STATUS_NO;
               subfile_no = 0;
           }
           else
           {
               /* 命令码错误 */
               return ERROR_COM;
           }
//       }
//       else
//       {
//           /* 其他路径正在升级 */
//           return ERROR_COM;
//       }
   }
   else
   {
       /* 新开始升级 */
       /* 重新执行命令 */
       if(upgrade_control_flag ==  UPGRADE_START)
       {
            if(OK != app_upgrade_bank_erase())
            {
                return ERROR_COM;
            }
            upgrade_values.file_total_num = 0;
            upgrade_values.upgrade_source = upgrade_source;
            upgrade_values.subfile_num = subfile_total_no;
            memcpy(upgrade_values.sha256,upgrade_sha256,UPGRADE_SHA256_LEN);
            memcpy(upgrade_values.upgrade_version,upgrade_version,UPGRADE_VERSION_LEN);
            upgrade_values.wait_subfile_no = 1;
            subfile_no = 1;
			upgrade_flag_clean_start();
       }
       else if (upgrade_control_flag ==  UPGRADE_STOP)
       {
           upgrade_values.upgrade_status = UPGRADE_STATUS_NO;
           subfile_no = 0;
       }
       else
       {
           /* 命令码错误 */
           return ERROR_COM;
       }
   }
   upgrade_values.upgrade_status = UPGRADE_STATUS_BEGIN;
   offset = 0;
   PIN_STORE_LONG(outdata,subfile_no,offset);
   *outdata_len = offset;
   upgrade_values.upgrade_source = upgrade_source;
   if(OK != app_control_upgrade_values_set(&upgrade_values))
   {
       return ERROR_COM;
   }
   return OK;
}

/**
* @brief 升级数据命令回调
* @param src               数据包头
* @param indata            输入报文
* @param indata_len        输入报文长度
* @param outdata           输出报文
* @param outdata_len       输出报文长度
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_data(uint8_t *src, uint8_t * indata,uint16_t indata_len,uint8_t * outdata,uint16_t *outdata_len)
{
    uint16_t offset = 0;
    uint32_t subfile_size = 0;
    uint32_t subfile_no = 0;
    UPGRADE_VALUES_t upgrade_values;
    char upgrade_sha256_arr[UPGRADE_SHA256_LEN];
	if(NULL != upgrade_flag_cleanTimerId)
	{
		xTimerReset(upgrade_flag_cleanTimerId,0);
	}
    if(OK != app_control_upgrade_values_get(&upgrade_values))
    {
        return ERROR_COM;
    }

    POUT_STORE_LONG(indata,subfile_no,offset);
    POUT_STORE_LONG(indata,subfile_size,offset);
    if(1 == subfile_no || subfile_no == upgrade_values.wait_subfile_no)
    {
        upgrade_values.upgrade_status = UPGRADE_STATUS_ON;
        upgrade_values.wait_subfile_no = subfile_no + 1;
    }
    else
    {
        /* 升级失败 */
        upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
        app_control_upgrade_values_set(&upgrade_values);
        return ERROR_COM;
    }

    if (OK != app_upgrade_flash_write(indata + offset,subfile_size,upgrade_values.file_total_num))
    {
        upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
        app_control_upgrade_values_set(&upgrade_values);
        return ERROR_COM;
    }
    upgrade_values.file_total_num += subfile_size;
    if(subfile_no >= upgrade_values.subfile_num)
    {
        upgrade_values.upgrade_status = UPGRADE_STATUS_REBOOT;
        //sha256校验
        sha256_context_t * upgrade_sha256_result;
        upgrade_sha256_result = ( sha256_context_t * )OS_MEM_MALLOC(sizeof(sha256_context_t),0);
        sha256_init(upgrade_sha256_result);
        unsigned int i = 0;
        for(;(i+1)*1024 < upgrade_values.file_total_num;i++){
            memcpy(temp,(const char *)ef_get_bak_app_start_addr() + i*1024,1024);
            sha256_update(upgrade_sha256_result,(const uint8_t*)temp,1024);
            memset(temp,0,1024);
        }
        int last_package = upgrade_values.file_total_num - (i)*1024;
        memcpy(temp,(const char *)ef_get_bak_app_start_addr() + i*1024,last_package);
        sha256_update(upgrade_sha256_result,(const uint8_t*)temp,last_package);
        sha256_final(upgrade_sha256_result,(unsigned char *)upgrade_sha256_arr,0);
        OS_MEM_FREE(upgrade_sha256_result,0);
        if(strncmp(upgrade_values.sha256,upgrade_sha256_arr,32) == 0){
            //定时重启
            PRINT_MSC_PACKET(32,(uint8_t *)upgrade_sha256_arr);
            upgradeTimerId = xTimerCreate("upgrade_Timer",pdMS_TO_TICKS(3*1000),pdFALSE,NULL,upgrade_interface_reset);
            xTimerStart(upgradeTimerId,0);
        }else{
            log_e(" upgrade_sha256 check fail \r\n");
            upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
            app_control_upgrade_values_set(&upgrade_values);
            return ERROR_COM;
        }                                                   
    }
    if(OK != app_control_upgrade_values_set(&upgrade_values))
    {
        return ERROR_COM;
    }
    return OK;
}

/**
* @brief 升级结果命令回调
* @param src               数据包头
* @param indata            输入报文
* @param indata_len        输入报文长度
* @param outdata           输出报文
* @param outdata_len       输出报文长度
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_result_get(uint8_t *src, uint8_t * indata,uint16_t indata_len,uint8_t * outdata,uint16_t *outdata_len)
{
	uint16_t upgrade_result = 0;
	uint16_t offset = 0;
	UPGRADE_VALUES_t upgrade_values;
	if(OK != app_control_upgrade_values_get(&upgrade_values))
	{
	   return ERROR_COM;
	}
	if(upgrade_values.upgrade_status == UPGRADE_STATUS_SUCCESS)
	{
	   upgrade_result = 0;
	}
	else if(upgrade_values.upgrade_status == UPGRADE_STATUS_FAIL)
	{
	   upgrade_result = 1;
	}
	else
	{
	   return ERROR_COM;
	}
	PIN_STORE_CHAR(outdata,upgrade_values.upgrade_source,offset);
	PIN_STORE_SHORT(outdata,upgrade_result,offset);
	PIN_STORE_BUFF(outdata,PCU_SW_VERSION,offset,VERSION_LENGTH);
	PIN_STORE_BUFF(outdata,PCU_HW_VERSION,offset,VERSION_LENGTH);
	*outdata_len = offset;
    upgrade_values.upgrade_source = 0;
	upgrade_values.upgrade_status = UPGRADE_STATUS_NO;
	if(OK != app_control_upgrade_values_set(&upgrade_values))
	{
		return ERROR_COM;
	}
   return OK;
}



/**
* @brief 升级模块初始化
* @return uint8_t OK：成功  ERROR_COM：失败
*/
int32_t app_upgrade_init(void)
{
    UPGRADE_VALUES_t upgrade_values;
	uint8_t upgrade_result = 0;
    if(OK != app_control_upgrade_values_get(&upgrade_values))
    {
       return ERROR_COM;
    }
    if(UPGRADE_STATUS_REBOOT == upgrade_values.upgrade_status )
    {
		if(iap_upgrade_result(&upgrade_result) != BSP_SUCCESS)
		{
			return ERROR_COM;
		}
		if(upgrade_result == IAP_UPGRADE_FAIL)
		{
			upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
		}
		else
		{
			upgrade_values.upgrade_status = UPGRADE_STATUS_SUCCESS;
		}
        
    }
	else if( UPGRADE_STATUS_BEGIN == upgrade_values.upgrade_status || UPGRADE_STATUS_ON == upgrade_values.upgrade_status)
	{
		upgrade_values.upgrade_status = UPGRADE_STATUS_FAIL;
	}
	
	if(OK != app_control_upgrade_values_set(&upgrade_values))
	{
		return ERROR_COM;
	}
    Msc_Cmd_Reg(CMD_SET_UPGRADE_CONTROL,app_upgrade_control);
    Msc_Cmd_Reg(CMD_SET_UPGRADE_DATA,app_upgrade_data);
    Msc_Cmd_Reg(CMD_GET_UPGRADE_RESULT,app_upgrade_result_get);

   /* 更新升级状态 */
   return OK;
}

#endif /* BOARD_PCU_EN */
